package main

import (
	"bufio"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"game/game-design-v.xnanz/export"
	"game/game-design-v.xnanz/gen"
	"game/game-design-v.xnanz/merge"
	"game/game-design-v.xnanz/meta"
	"io"
	"os"
	"sort"
	"strings"
)

func main() {
	//测试用导出配置
	// args := []string{
	// 	"export",
	// 	"-reader excel",
	// 	"-mode full D:\\Git\\codex001\\codex001-config\\excelmd5",
	// 	"-sourcehome D:\\Git\\codex001\\codex001-config\\src\\",
	// 	"-exportfor csv D:\\Git\\codex001\\codex001-config\\export\\server-csv\\ useFileName server,server&cn",
	// }
	// 测试用生成Java代码的参数
	// args := []string{
	// 	"gen",
	// 	"-template D:\\Git\\codex001\\codex001-config\\java-template.txt",
	// 	"-arg abstract_output_path D:\\Git\\codex001\\codex001-servermain\\codex001-server\\codex001-design\\src\\main\\java\\org\\xnanz\\codex001\\design\\module\\autogen\\",
	// 	"-arg subclass_output_path D:\\Git\\codex001\\codex001-servermain\\codex001-server\\codex001-design\\src\\main\\java\\org\\xnanz\\codex001\\design\\module\\",
	// 	"-sourcehome D:\\Git\\codex001\\codex001-config\\export\\server-csv\\",
	// 	"-reader csv",
	// 	"-genfor server,server&cn",
	// }
	// 测试用生成ts代码的参数
	// args := []string{
	// 	"gen",
	// 	"-define name:1 type:2 tag:4 comment:3 bothTag:all serverTag:server clientTag:client ignoreTag:-",
	// 	"-template D:\\Git\\xuedao2-project\\ts-template.txt",
	// 	"-arg output_path D:\\cocos\\test-design\\assets\\scripts\\design\\autogen\\",
	// 	"-sourcehome D:\\Git\\xuedao2-project\\version-exports\\client-ajson\\",
	// 	"-reader tjson",
	// }
	//合并文件
	// args := []string{
	// 	"merge",
	// 	"-sourcehome D:\\Git\\xuedao2-project\\version-exports\\client-ajson\\",
	// 	"-outputfile D:\\Git\\xuedao2-project\\version-exports\\cfg.json",
	// }
	//生成目录
	// args := []string{
	// 	"catalog",
	// 	"-template D:\\Git\\xuedao2-project\\ts-catalog-template.txt",
	// 	"-sourcehome D:\\cocos\\test-design\\assets\\scripts\\design\\autogen\\",
	// 	"-arg output_path D:\\cocos\\test-design\\assets\\scripts\\design\\",
	// }

	//打包正式环境参数
	args := os.Args[1:]

	for _, v := range args {
		fmt.Println(v)
	}

	if args[0] == "export" {
		exportFunc(args)
	} else if args[0] == "gen" {
		genFunc(args)
	} else if args[0] == "merge" {
		mergeFunc(args)
	} else if args[0] == "catalog" {
		merge.CatalogFun(args)
	}
}

func genFunc(args []string) {
	genArgs := gen.NewGenArgs(args)
	if !genArgs.Check() {
		fmt.Println("缺少必要运行参数")
		return
	}
	fileList, err := os.ReadDir(genArgs.SourceHome)
	if err != nil {
		fmt.Println(err)
		return
	}
	lines := gen.ReadTemplateFile(genArgs.TemplateFile)

	var readerIO export.IDesignIO = genArgs.Reader
	for _, f := range fileList {
		if strings.HasPrefix(f.Name(), "~$") {
			continue
		}
		if f.IsDir() {
			continue
		}
		fileFullPath := genArgs.SourceHome + string(os.PathSeparator) + f.Name()
		designFiles, err := readerIO.Read(fileFullPath)
		if err != nil {
			fmt.Println(err)
			continue
		}
		designFile := designFiles[0]
		classMeta := meta.Build(designFile)

		gen.CurrFile = classMeta.FileName
		gen.Params["classMeta"] = classMeta

		classBlocks := gen.NewClassBlock(lines)
		for _, clazz := range classBlocks {
			os.Mkdir(clazz.FileDir, 0755)
			content := clazz.BuildResult()

			if clazz.GenIfAbsent {
				_, err := os.Stat(clazz.FileDir + clazz.FileName)
				if err != nil && os.IsNotExist(err) {
					fmt.Println("导出代码=>\t", clazz.FileName)
					err := os.WriteFile(clazz.FileDir+clazz.FileName, []byte(content), 0666)
					if err != nil {
						fmt.Println(err)
					}
				}
			} else {
				fmt.Println("导出代码=>\t", clazz.FileName)
				err := os.WriteFile(clazz.FileDir+clazz.FileName, []byte(content), 0666)
				if err != nil {
					fmt.Println(err)
				}
			}
		}
	}
}

func exportFunc(args []string) {
	exportArgs := export.NewExportArgs(args)
	fileList, err := os.ReadDir(exportArgs.SourceHome)
	if err != nil {
		fmt.Println(err)
		return
	}
	var readerIO export.IDesignIO = exportArgs.Reader

	var md5Map map[string]string
	if exportArgs.Mode == "fast" {
		md5Map = *readMd5(exportArgs.ModeFile)
		fmt.Println("使用快速模式导出")
	} else {
		md5Map = make(map[string]string, 100)
		fmt.Println("使用完整模式导出")

		for _, exportfor := range exportArgs.Exportfors {
			os.RemoveAll(exportfor.OutputFolder)
		}
	}

	for _, file := range fileList {
		if strings.HasPrefix(file.Name(), "~$") {
			continue
		}
		if file.IsDir() {
			continue
		}
		if exportArgs.Mode == "fast" {
			md5, ok := md5Map[file.Name()]
			if ok {
				currMd5, ok := fileMd5(exportArgs.SourceHome + file.Name())
				if ok {
					if md5 == currMd5 {
						fmt.Println("文件未发生变化\t" + file.Name())
						continue
					} else {
						md5Map[file.Name()] = currMd5
					}
				}
			} else {
				currMd5, ok := fileMd5(exportArgs.SourceHome + file.Name())
				if ok {
					md5Map[file.Name()] = currMd5
				}
			}
		}

		fileFullPath := exportArgs.SourceHome + file.Name()
		designFiles, err := readerIO.Read(fileFullPath)
		if err != nil {
			fmt.Println("读取文件", file.Name(), "发生错误", err)
			continue
		}
		//导出除语言表外的配置
		for _, dFile := range designFiles {
			for _, exportfor := range exportArgs.Exportfors {
				dFile.OutputNameType = exportfor.NameForm

				var writerIO export.IDesignIO = export.GetDesignIO(exportfor.Way)
				writerIO.Write(dFile, exportfor)
			}
		}
	}

	if exportArgs.Mode == "fast" {
		writeMd5(exportArgs.ModeFile, md5Map)
	}
}

func mergeFunc(args []string) {
	mergeArgs := merge.NewMergeArgs(args)
	merge.Merge(mergeArgs)
}

func fileMd5(filePath string) (string, bool) {
	file, err := os.Open(filePath)
	if err != nil {
		return "", false
	}
	defer file.Close()

	hash := md5.New()
	if _, err := io.Copy(hash, file); err != nil {
		return "", false
	}

	return hex.EncodeToString(hash.Sum(nil)), true
}

func readMd5(md5File string) *map[string]string {
	md5Map := make(map[string]string, 100)
	file0, err := os.Open(md5File)
	if err != nil {
		return &md5Map
	}
	scanner := bufio.NewScanner(file0)
	for scanner.Scan() {
		line := scanner.Text()
		parts := strings.Split(line, "=")
		if len(parts) >= 2 {
			md5Map[parts[0]] = parts[1]
		}
	}
	return &md5Map
}

func writeMd5(md5File string, md5Map map[string]string) {
	keyArray := make([]string, 0, len(md5Map))
	for key := range md5Map {
		keyArray = append(keyArray, key)
	}
	sort.Strings(keyArray)

	file, err := os.OpenFile(md5File, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer file.Close()

	for _, key := range keyArray {
		md5Value := md5Map[key]
		file.WriteString(string(fmt.Sprintf("\n%s=%s", key, md5Value)))
	}
}
